//
//  ProductManager.m
//  freeLance
//
//  Created by s.zalozniy on 3/27/13.
//  Copyright (c) 2013 Mozi Development. All rights reserved.
//

#import "Utils.h"
#import "Reachability.h"
#import "SVProgressHUD.h"
#import "CoreDataRoutines.h"
#import "UIImage+Scale.h"

#import "ProductManager.h"

#define SECONDS_IN_DAY (24 * 60 * 60)

#define PRODUCT_AND_CATEGORIES_URL BASE_URL @"api.json"

#define IMAGE_PATH_KEY @"imagePathKey"
#define IMAGE_URL_KEY @"imageUrlKey"


@interface ProductManager()

@property (nonatomic, strong) Reachability *serviceReachability;
@property (nonatomic, strong) MDResourceLoader *resourceLoader;
@property (nonatomic, assign) NSInteger hasFail;
@property (nonatomic, assign) BOOL silentMode;
@property (nonatomic, assign) CGFloat totalProgress;
@property (nonatomic, assign) CGFloat loadingStep;
@property (nonatomic, assign) BOOL isResizeingImage;
@property (nonatomic, strong) NSMutableArray *imageToResize;
@property (nonatomic, assign) BOOL synhronizationInProgress;

@end


@implementation ProductManager

static ProductManager *currentProductManager = nil;


#pragma mark - Static methods

+(ProductManager *) sharedInstance {
    @synchronized (self) {
        if (!currentProductManager) {
            currentProductManager = [[ProductManager alloc] init];
        }
    }
    
	return currentProductManager;
}


#pragma mark - Instance initialization

-(id) init {
	self = [super init];
	if (!self) {
		return nil;
	}
    _resourceLoader = [[MDResourceLoader alloc] init];
    self.resourceLoader.delegate = self;
    self.imageToResize = [NSMutableArray array];
    
    self.delegate = self;
    self.serviceReachability = [Reachability reachabilityForInternetConnection];
	[self.serviceReachability startNotifier];
    [self performSelector:@selector(setupReachabilityObserver)
               withObject:nil
			   afterDelay:3.0f];
//    [self performSelector:@selector(reachabilityChanged:)
//               withObject:nil
//               afterDelay:3.5f];
	return self;
}


#pragma mark - Interface methods

-(void) loadProductsAndCategories {
    [self loadFromUrl:PRODUCT_AND_CATEGORIES_URL
           withParams:nil
          andUserInfo:nil];
    self.synhronizationInProgress = YES;
    if ([self  timeIntervalSinceLastUpdate] > 31 * SECONDS_IN_DAY) {
        self.silentMode = NO;
        [SVProgressHUD showWithStatus:NSLocalizedString(@"Загрузка даных", nil)
                             maskType:SVProgressHUDMaskTypeGradient];
    } else {
        self.silentMode = YES;
    }
}


#pragma mark - Private methods

-(id) createObjectForProperty:(NSString *)propertyName usingExistingObject:(id)anotherObject {
    if ([propertyName isEqualToString:@"categories"]) {
        NSInteger objectCount = [anotherObject count];
        NSMutableArray *categories = [NSMutableArray arrayWithCapacity:objectCount];
        for (NSInteger currentIndex = objectCount; currentIndex > 0; currentIndex--) {
            Categories *singleCategory = [[Categories alloc] init];
            [categories addObject:singleCategory];
        }
        return categories;
    } else if ([propertyName isEqualToString:@"collections"]) {
        NSInteger objectCount = [anotherObject count];
        NSMutableArray *collections = [NSMutableArray arrayWithCapacity:objectCount];
        for (NSInteger currentIndex = objectCount; currentIndex > 0; currentIndex--) {
            Collections *singleCollection = [[Collections alloc] init];
            [collections addObject:singleCollection];
        }
        return collections;
    } else if ([propertyName isEqualToString:@"products"]) {
        NSInteger objectCount = [anotherObject count];
        NSMutableArray *products = [NSMutableArray arrayWithCapacity:objectCount];
        for (NSInteger currentIndex = objectCount; currentIndex > 0; currentIndex--) {
            Products *singleProduct = [[Products alloc] init];
            [products addObject:singleProduct];
        }
        return products;
    }

    return nil;
}


-(void) setIsResizeingImage:(BOOL)value {
//    static int currentlyResized = 1;
//    currentlyResized += value ? 0 : -1;
    
    if (!value  && self.imageToResize.count) {
        NSDictionary *userInfo = [self.imageToResize lastObject];
//        while (userInfo && currentlyResized < 10) {
            NSString *imagePath = [userInfo objectForKey:IMAGE_PATH_KEY];
            NSString *imageUrl = [userInfo objectForKey:IMAGE_URL_KEY];
            [self resizeImage:imagePath url:imageUrl];
            [self.imageToResize removeLastObject];
//            currentlyResized++;
//        }
        
        if (!self.silentMode && !self.synhronizationInProgress){
            [SVProgressHUD showWithStatus:[NSLocalizedString(@"Адаптация картинок под Ваше устройство, осталось - ", nil) stringByAppendingFormat:@"%i",self.imageToResize.count + 1]
                                 maskType:SVProgressHUDMaskTypeGradient];
        }
        return;
    }
    
    if (!value && !self.synhronizationInProgress) { //&& !currentlyResized) {
        [SVProgressHUD showSuccessWithStatus:@""];
        [[NSNotificationCenter defaultCenter] postNotificationName:ProductManagerFinishLoadingAndSynchronization
                                                            object:nil];
    }
    _isResizeingImage = value;
}


-(void) setupReachabilityObserver {
    [[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(reachabilityChanged:)
												 name:kReachabilityChangedNotification
											   object:self.serviceReachability];
}


-(void) removeReachabilityObserver {
	[[NSNotificationCenter defaultCenter] removeObserver:self
													name:kReachabilityChangedNotification
												  object:self.serviceReachability];
}


-(void) setLastUpdateNow {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:[NSDate date] forKey:LAST_UPDATE_KEY];
    [userDefaults synchronize];
}


-(NSTimeInterval) timeIntervalSinceLastUpdate {
    NSDate *lastUpdate = [[NSUserDefaults standardUserDefaults] objectForKey:LAST_UPDATE_KEY];
    if (!lastUpdate) {
        return DBL_MAX - 1;
    }
    
    return [[NSDate date] timeIntervalSinceDate:lastUpdate];
}


-(BOOL) isNetworkReachable {
    return [self.serviceReachability isReachable] && [self.serviceReachability isReachableViaWiFi];
}


-(NSString *) imageFolder {
    NSString *imageFolder = [NSString stringWithFormat:@"%@/images", [Utils applicationCacheDirectory]];
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:imageFolder]) {
        return imageFolder;
    }
    
    NSError *error = nil;
    if (![[NSFileManager defaultManager] createDirectoryAtPath:imageFolder
                                  withIntermediateDirectories:NO
                                                   attributes:nil
                                                      error:&error]) {
        $l(@"error - %@", [error localizedDescription]);
        $fail(YES, @"Can not create folder for images");
    }
    
    return imageFolder;
}


-(NSString *) imageThumbnail60Folder {
    NSString *imageFolder = [NSString stringWithFormat:@"%@/imagesThumbnail60", [Utils applicationCacheDirectory]];
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:imageFolder]) {
        return imageFolder;
    }
    
    NSError *error = nil;
    if (![[NSFileManager defaultManager] createDirectoryAtPath:imageFolder
                                   withIntermediateDirectories:NO
                                                    attributes:nil
                                                         error:&error]) {
        $l(@"error - %@", [error localizedDescription]);
        $fail(YES, @"Can not create folder for images");
    }
    
    return imageFolder;
}


-(NSString *) imageThumbnail200Folder {
    NSString *imageFolder = [NSString stringWithFormat:@"%@/imagesThumbnail200", [Utils applicationCacheDirectory]];
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:imageFolder]) {
        return imageFolder;
    }
    
    NSError *error = nil;
    if (![[NSFileManager defaultManager] createDirectoryAtPath:imageFolder
                                   withIntermediateDirectories:NO
                                                    attributes:nil
                                                         error:&error]) {
        $l(@"error - %@", [error localizedDescription]);
        $fail(YES, @"Can not create folder for images");
    }
    
    return imageFolder;
}


-(void) startSynchronizationWithDB {
    [[CoreDataRoutines sharedInstance] startSynchronization];
    self.synhronizationInProgress = NO;
    [self setLastUpdateNow];
    if (self.hasFail) {
        $l(@"Not all Resources has been loaded,failed - %i", self.hasFail);
        if (!self.silentMode) {
            self.totalProgress = 0.0f;
            [SVProgressHUD showSuccessWithStatus:NSLocalizedString(@"Synchronized finished - with errors", nil)];
        }
    } else {
        if (!self.silentMode) {
            self.totalProgress = 0.0f;
            [SVProgressHUD showSuccessWithStatus:NSLocalizedString(@"Synchronized finished - successfully", nil)];
        }
    }
    
    if (!self.silentMode && !self.imageToResize.count) {
        [[NSNotificationCenter defaultCenter] postNotificationName:ProductManagerFinishLoadingAndSynchronization
                                                            object:nil];
    }
}


-(void) resizeImage:(NSString *)imagePath url:(NSString *)imageUrl {
    self.isResizeingImage = YES;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^() {
        @autoreleasepool {
            NSString *imagePathCopy = [imagePath copy];
            NSString *imageUrlCopy = [imageUrl copy];
            NSData *imageData = [NSData dataWithContentsOfFile:imagePathCopy];
            UIImage *generalImage = [UIImage imageWithData:imageData];
            
            UIImage *scaled200Image = nil;
            UIImage *scaled60Image = nil;
            NSInteger scale = (IS_RETINA) ? 2 : 1;
            if (IS_IPAD) {
                scaled200Image = [generalImage scaleProportionalToSize:CGSizeMake(scale * 200, scale * 200)];
                scaled60Image = [generalImage scaleProportionalToSize:CGSizeMake(scale * 60, scale * 60)];
            } else {
                scaled200Image = [generalImage scaleProportionalToSize:CGSizeMake(scale * 138, scale * 138)];
                scaled60Image = [generalImage scaleProportionalToSize:CGSizeMake(scale * 69, scale * 69)];
            }
            
            imageData = UIImagePNGRepresentation(scaled200Image);
            NSString *fileName = [[self imageThumbnail200Folder] stringByAppendingPathComponent:[Utils md5:imageUrlCopy]];
            NSError *error = nil;
            [imageData writeToFile:fileName options:NSDataWritingAtomic error:&error];
            if (error) {
                $l(@"%@", [error localizedDescription]);
            }
            
            imageData = UIImagePNGRepresentation(scaled60Image);
            fileName = [[self imageThumbnail60Folder] stringByAppendingPathComponent:[Utils md5:imageUrlCopy]];
            [imageData writeToFile:fileName atomically:NO];
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            self.isResizeingImage = NO;
        });
	});
}

#pragma mark - Notification observers

-(void) reachabilityChanged:(NSNotification *)notification {
    if (![self isNetworkReachable]) {
        return ;
    }
//    if ([self timeIntervalSinceLastUpdate] > SECONDS_IN_DAY) {
//        [self loadProductsAndCategories];
//    }
}


#pragma mark - Delegated methods

-(void) dataProceedFailed:(MDSuperDataSource *)dataSource request:(ASIFormDataRequest *)request {
    if (!self.silentMode) {
        [SVProgressHUD showErrorWithStatus:NSLocalizedString(@"Проверте Ваше интернет соидинение", nil)];
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Проблемы с соеденением. Попробывать снова?", nil)
                                                        message:nil
                                                       delegate:self
                                              cancelButtonTitle:NSLocalizedString(@"Да", nil)
                                              otherButtonTitles: nil];
        [alert show];
    }
}


-(void) didProceedData:(MDSuperDataSource *)dataSource request:(ASIFormDataRequest *)request responseData:(NSDictionary *)responseData {
    if (request.responseStatusCode != 200) {
        [self dataProceedFailed:dataSource request:request];
    }
    
    NSInteger resourceCount = 0;
    self.hasFail = 0;
    self.resourceLoader.shouldStartImmediate = NO;
    
    if (!self.silentMode) {
        [SVProgressHUD showProgress:0.0f
                             status:NSLocalizedString(@"Загрузка картинок", nil)
                           maskType:SVProgressHUDMaskTypeGradient];
    }
    
    for (Products *product in self.products) {
        for (NSString *imageUrl in product.images) {
            NSString *fileName = [[self imageFolder] stringByAppendingPathComponent:[Utils md5:imageUrl]];
            
            if (![[NSFileManager defaultManager] fileExistsAtPath:fileName]) {
                [self.resourceLoader downloadMediaFileWithUrl:[NSURL URLWithString:imageUrl]
                                                   toFilePath:fileName
                                                 withUserInfo:@{IMAGE_PATH_KEY : fileName,
                                                                 IMAGE_URL_KEY : imageUrl}];
                resourceCount++;
            }
        }
    }
    self.resourceLoader.shouldStartImmediate = YES;
    
    if (resourceCount) {
        self.totalProgress = 0.0f;
        self.loadingStep = 1.0f / resourceCount;
        [self.resourceLoader start];
    } else {
        [self startSynchronizationWithDB];
    }
}


-(void) resourceLoader:(MDResourceLoader *)resourceLoader finishedLoadingResourceFromUrl:(NSURL *)url withUserInfo:(NSDictionary *)userInfo {
    if (!self.silentMode) {
        self.totalProgress += self.loadingStep;
        [SVProgressHUD showProgress:self.totalProgress
                             status:NSLocalizedString(@"Загрузка картинок", nil)
                           maskType:SVProgressHUDMaskTypeGradient];
    }
    
    NSString *imagePath = [userInfo objectForKey:IMAGE_PATH_KEY];
    NSString *imageUrl = [userInfo objectForKey:IMAGE_URL_KEY];
    if (self.isResizeingImage) {
        [self.imageToResize addObject:userInfo];
        return;
    }
    [self resizeImage:imagePath url:imageUrl];
}


-(void) resourceLoader:(MDResourceLoader *)resourceLoader failedLoadingResourceFromUrl:(NSURL *)url withUserInfo:(NSDictionary *)userInfo error:(NSError *)error {
    $l(@"Error loading image - %@", url);
    
    NSString *fileName = [userInfo objectForKey:IMAGE_PATH_KEY];
    NSError *error2 = nil;
    [[NSFileManager defaultManager] removeItemAtPath:fileName error:&error2];
    
    if (error2) {
        $l(@"Error while deleting file - %@", [error2 localizedDescription]);
    }
    
    if (!self.silentMode) {
        self.totalProgress += self.loadingStep;
        [SVProgressHUD showProgress:self.totalProgress
                             status:NSLocalizedString(@"Загрузка картинок", nil)
                           maskType:SVProgressHUDMaskTypeGradient];
    }
    
    self.hasFail++;
}


-(void) resourceLoaderFinishedLoadingResources:(MDResourceLoader *)resourceLoader {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self startSynchronizationWithDB];
    });
}

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    [self loadProductsAndCategories];
}

@end